package com.xcity.game.assist;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Player;
import com.xcity.db.entity.Relation2;
import com.xcity.game.buildv2.BuildV2;
import com.xcity.game.buildv2.BuildV2.State;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.conquests.ConquestsService;
import com.xcity.game.event.GameEvents;
import com.xcity.game.formation.Formation;
import com.xcity.game.player.PlayerService;
import com.xcity.game.player.cache.PlayerCacheService;
import com.xcity.game.relation.RelationService;
import com.xcity.game.relation.Relations;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.request.AssistBuildRequest;
import com.xcity.pomelo.request.AssistListRequest;
import com.xcity.pomelo.request.AssistUnAssistRequest;
import com.xcity.pomelo.request.AssistInviteRequest;
import com.xcity.pomelo.response.AssistInviteResponse;
import com.xcity.pomelo.response.AssistListResponse;
import com.xcity.pomelo.response.AssistUnAssistResponse;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.Response;
import com.xcity.util.BackDoorHandler;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.time.DayListener;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.Service;
import naga.x.service.ServiceException;

@OPHandler
public class AssistService implements Service, DayListener, EventListener{

	protected static final Logger LOG = LoggerFactory.getLogger(AssistService.class);
	
	public static int ASSIST_CD_MILLISECOND = 5 * 1000;//BackDoorHandler.CHEAT_ENABLE?60 * 1000:30 * 60 * 1000;
	
	@Override
	public void startup() throws ServiceException {
		App.getApp().getEventManager().register(this);
		TimeUpdater.getInstance().addDayListener(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public String getId() {
		return getClass().getName();
	}

	@Override
	public int[] getEventTypes() {
		return new int[]{
				GameEvents.EVENT_PLAYER_LOGIN};
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
		case GameEvents.EVENT_PLAYER_LOGIN:
			playerLogin(event.getParameter());
			break;
		default:
			break;
		}
	}
	
	protected void playerLogin(Player player){
		int today = TimeUpdater.getInstance().today();
		player.getBuildings2().tryResetAssist(today);
	}

	@PomeloOP(PomeloRoute.ASSIST_INVITE)
	protected void requestInvite(Session session, AssistInviteRequest req){
		Player player = session.getClient();
		long assistantId = req.getAssistant();
		Player assistant = App.getApp().getServiceManager().get(PlayerCacheService.class).find(assistantId);
		if(assistant == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_PLAYER));
			return;
		}
		
		RelationService rs = App.getApp().getServiceManager().get(RelationService.class);
		if(!rs.isFriend(player, assistant, false)){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NOT_FRIEND));
			return;
		}
		
		
		List<Employee> eList = null;
		Formation f = assistant.getFormations().get(Formation.TYPE_NORMAL);
		if (f != null) {
			eList = Arrays.asList(f.getUnits());
		}

		long[] eids = new long[]{0, 0, 0, 0};//影响后面日志
		if(eList == null || eList.size() != eids.length){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_EMPLOYEE_COUNT));
			return;
		}
		for(int i = 0; i < eids.length; i++){
			Employee e = eList.get(i);
			if(e == null){
				player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_EMPLOYEE_ERROR));
				return;
			}
			eids[i] = e.getId();
		}
		int today = TimeUpdater.getInstance().today();
		
		//这个人今天是否协防过
		player.getBuildings2().tryResetAssist(today);
		if(player.getBuildings2().checkIsMaxAssist()){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_BUILD_MAX_ASS_COUNT));
			return;
		}
		if(player.getBuildings2().checkIsAssist(assistantId)){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_BUILD_ARLREADY_ASS_TODAY));
			return;
		}
		
		//建筑及状态
		BuildV2 targetBuild = player.getBuildings2().find(req.getBuildid());
		if(targetBuild == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_BUILD));
			return;
		}
		String err = targetBuild.canBeAssisted();
		if(err != null){
			player.send(new HintResponse(req.getSerial(), err));
			return;
		}
		if(player.getBuildings2().getAssistBuildByAssistant(assistantId) != null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_HAS_ASSIST));
			return;
		}
		long now = TimeUpdater.getInstance().now();
		
		//每个建筑半小时协助CD
		long cd = targetBuild.getAssistTime() + ASSIST_CD_MILLISECOND - now;
		if(cd > 0){
			if(cd > ASSIST_CD_MILLISECOND){
				cd = ASSIST_CD_MILLISECOND;
			}
			player.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.ASSIST_BUILD_IN_CD, (cd / 1000) + 1)));
			return;
		}
		
//		AssistInvite invite = target.getAssists().tryAddNewInvite(assistantId, req.getBuildid());
//		if(invite == null){
//			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_HAS_INVITE));
//			return;
//		}
		targetBuild.removeAllEmployee(null);//没有处理员工经验下发
		int lastTake = targetBuild.beAssisted(assistant.getId(), now);
		player.getBuildings2().addNewAssistantId(assistant.getId());
//		assistant.getAssists().assistBuildList.clear();
		AssistBuild assbuild = assistant.getAssists().tryAddNewAssistBuild(player.getId(), targetBuild.getId(), eids, now);
		
		player.send(new AssistInviteResponse(req.getSerial(), assbuild, assistant, targetBuild.getState(), now, lastTake));
		LOG.info("[ASS INVITE]ID[{}]BUILD[{}]ASSID[{}]EIDS[{},{},{},{}]", player.getId(), targetBuild.getId(), assistantId, eids[0], eids[1], eids[2], eids[3]);
	}

	/**
	 * 请求协助好友列表 选择哪个好友协助防守
	 */
	@PomeloOP(PomeloRoute.ASSIST_FRIEND_LIST)
	protected void requestAssistList(Session session, AssistListRequest req){
		Player player = session.getClient();
		RelationService rs = App.getApp().getServiceManager().get(RelationService.class);
		Relations rels = rs.findRelations(player);
//		List<Relation2> friendRels = rels.getRelations(Relation2.TYPE_FRIEND);
		int size = rels.sizeOf(Relation2.TYPE_FRIEND);//friendRels.size();
		final List<Player> friends = new ArrayList<Player>(size);
		if (size > 0) {
			PlayerCacheService as = App.getApp().getServiceManager().get(PlayerCacheService.class);
			rels.forEach(Relation2.TYPE_FRIEND, new Consumer<Relation2>() {
				@Override
				public void accept(Relation2 rel) {
					Player friend = as.find(rels.getDestId(rel));
					if (friend != null) {
						friends.add(friend);
					}
				}
			});
		}
		player.send(new AssistListResponse(req.getSerial(), player, friends));
	}

	/**
	 * 请求取消协防
	 */
	@PomeloOP(PomeloRoute.ASSIST_UNASSIST)
	protected void requestUnAssist(Session session, AssistUnAssistRequest req){
		Player player = session.getClient();
		int bid = req.getBuildid();

		BuildV2 targetBuild = player.getBuildings2().find(bid);
		if(targetBuild == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_BUILD));
			return;
		}
		if(targetBuild.getState() != State.ASSISTED){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_ASSIST_BUILD));
			return;
		}
		Player assistant = App.getApp().getServiceManager().get(PlayerCacheService.class).find(targetBuild.getAssistId());
		if(assistant == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_ASSIST_BUILD));
			return;
		}
		int[] ret = targetBuild.unAssisted(assistant, false, Cause.ASS_CANCEL);
		player.send(new AssistUnAssistResponse(req.getSerial(), targetBuild, ret[0]));
	}
	
//	@PomeloOP(PomeloRoute.ASSIST_BUILD)
	@Deprecated
	protected  void requestAssistBuild(Session session, AssistBuildRequest req){
		Player player = session.getClient();
		Player owner = App.getApp().getServiceManager().get(PlayerCacheService.class).find(req.getOwnerId());
		if(owner == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_PLAYER));
			return;
		}
		BuildV2 targetBuild = owner.getBuildings2().find(req.getBuildId());
		if(targetBuild == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_BUILD));
			return;
		}
		String err = targetBuild.canBeAssisted();
		if(err != null){
			player.send(new HintResponse(req.getSerial(), err));
			return;
		}

		boolean removed = player.getAssists().tryRemoveInvite(req.getOwnerId(), req.getBuildId());
		if(!removed){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_NO_INVITE));
			return;
		}
		
		long[] eids = req.getEids();
		if(eids.length != 4){
			player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_EMPLOYEE_COUNT));
			return;
		}
		for(int i = 0; i < eids.length; i++){
			long eid = eids[i];
			Employee e = player.getEmployees().get(eid);
			if(e == null){
				player.send(new HintResponse(req.getSerial(), MessageConst.ASSIST_EMPLOYEE_ERROR));
				return;
			}
		}
		
		//TODO 判断员工
		
		long now = TimeUpdater.getInstance().now();
		targetBuild.beAssisted(player.getId(), now);
		
		player.getAssists().tryAddNewAssistBuild(owner.getId(), targetBuild.getId(), eids, now);
		//TODO
		player.send(new Response(req.getSerial()));
	}

	@Override
	public boolean dayChanged() {
		int today = TimeUpdater.getInstance().today();
		Collection<Player> players = App.getApp().getServiceManager().get(PlayerService.class).getOnlinePlayers();
		for(Player player : players){
			player.getBuildings2().tryResetAssist(today);
		}
		return true;
	}
}
